home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Graphics Samples / Test Cubics (cubic to quad) ƒ / cubic library(Cubics2).c next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  11.3 KB  |  505 lines  |  [TEXT/MPS ]

  1. /**\
  2. |**| =====================================================================
  3. |**|
  4. |**|    FILENAME
  5. |**|        cubic library(Cubics2).c
  6. |**|    
  7. |**|    DESCRIPTION
  8. |**|        This library is used by the TestCubics Quickdraw GX
  9. |**|        sample program to create and use Cubics.
  10. |**|    
  11. |**|    COPYRIGHT
  12. |**|        ©1992-1996 Copyright Apple Computer, Inc.
  13. |**|        All rights reserved.
  14. |**|    
  15. |**|    Change History:
  16. |**|
  17. |**|        4/96    cnn        Updated the header filename, description, and
  18. |**|                    copyright. Updated #includes to support changed
  19. |**|                    GX Library names. Changed fixed to Fixed. Changed
  20. |**|                    fract to Fract.
  21. |**|
  22. |**| =====================================================================
  23. \**/
  24.  
  25. #include "FixMath.h"
  26.  
  27. #include "GraphicsLibraries.h"
  28.  
  29. /* this is the structyre for a single cubic -- from the library routines */
  30.  
  31. /*
  32.  
  33.             typedef struct    {                
  34.             
  35.                     gxPoint            a;
  36.                     gxPoint            b;
  37.                     gxPoint            c;
  38.                     gxPoint            d;
  39.                     
  40.             } cubic;
  41.  
  42. */
  43.  
  44. typedef struct    {                /* this structure contains the cached cubic coefficients */
  45.     
  46.         Fixed            ax, ay;
  47.         Fixed            bx, by;
  48.         Fixed            cx, cy;
  49.         Fixed            dx, dy;
  50.             
  51. } xcubic;
  52.  
  53. typedef struct    {                /* this structure is just for a gxPath */
  54.  
  55.         long        contours;
  56.         long        count;
  57.         long        flags;
  58.         gxPoint        data[ 32 ];
  59.  
  60. } SmallPath;
  61.  
  62. /* internal prototypes */
  63.  
  64. void CubicPath( SmallPath *pathptr, const cubic *cube, const long count );
  65.  
  66. long CountQuadratics( const cubic * );
  67. long xCountQuadratics( const cubic * );
  68.  
  69. gxPoint *ComputePoints( const cubic *cube, long    count,  gxPoint *storage );
  70.  
  71. /* now we define some macros to calculate the inner products */
  72.         
  73. #define xcube(xc,u) (FracMul(FracMul(FracMul((xc)->ax,(u))+(xc)->bx,(u))+(xc)->cx,(u))+(xc)->dx)
  74. #define    ycube(xc,u) (FracMul(FracMul(FracMul((xc)->ay,(u))+(xc)->by,(u))+(xc)->cy,(u))+(xc)->dy)
  75.  
  76. #define xcubeprime(xc,u) (FracMul(FracMul((3*(xc)->ax),(u))+(2*(xc)->bx),(u))+(xc)->cx)
  77. #define ycubeprime(xc,u) (FracMul(FracMul((3*(xc)->ay),(u))+(2*(xc)->by),(u))+(xc)->cy)
  78.  
  79. /*--------------------------------------------------------------------------------
  80.  
  81.     NewCubic
  82.     
  83.         this routine makes a new cubic that has a tolerance of one pixel.
  84.         
  85.             cubic            ->            a pointer to the cubic
  86.  
  87. --------------------------------------------------------------------------------*/
  88.  
  89. gxShape NewCubic( const cubic *cube )
  90. {    
  91.     SmallPath        pathrec;
  92.  
  93.     CubicPath( &pathrec, cube, xCountQuadratics( cube ) );
  94.     
  95.     /* now we are ready to create the gxPath */
  96.  
  97.     return( GXNewPaths((gxPaths *) &pathrec ) );
  98. }
  99.  
  100. /*--------------------------------------------------------------------------------
  101.  
  102.     NewCubic2
  103.     
  104.         this routine is the same as above except that it has an optional
  105.         parameter for determining how many points to include in a gxPath.  the number
  106.         determines the number of points 'off' the gxCurve which are needed.
  107.  
  108.             cubic            ->            a pointer to the cubic
  109.         
  110.         if you use this routine you should link it in with another which determines
  111.         the number of points to be used. here is an example that depends on a global
  112.         variable 'gerror' of type extended.  also, see the 'optimized' example for
  113.         'xCountQuadratics' futher below.
  114.         
  115.         extended gerror = 1.0;
  116.         
  117.         long CountQuadratics( const cubic *cube )
  118.             {
  119.                 long            count;
  120.                 extended    a, n;
  121.                 
  122.                 extended ax;
  123.                 extended ay;
  124.                 
  125.                 ax = Fix2X( - cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x );
  126.                 ay = Fix2X( - cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y );
  127.                 
  128.                 a = sqrt( ax * ax + ay * ay );
  129.                 
  130.                 n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
  131.             
  132.                 count = ceil( n );
  133.             
  134.                 if( count <= 0 ) count += 1;
  135.             
  136.                 return( count );
  137.             }
  138.  
  139. --------------------------------------------------------------------------------*/
  140.  
  141. gxShape NewCubic2( const cubic *cube, const long count )
  142. {    
  143.     SmallPath        pathrec;
  144.  
  145.     CubicPath( &pathrec, cube, ( count <= 0 ) ? CountQuadratics( cube ) : count );
  146.  
  147.     /* now we are ready to create the gxPath */
  148.         
  149.     return( GXNewPaths((gxPaths *) &pathrec ) );
  150. }
  151. /*--------------------------------------------------------------------------------
  152.  
  153.     CubicPath
  154.     
  155.         this routine fills in a data structure for a gxPath with the information
  156.         of a cubic.
  157.         
  158.             pathptr        ->        a pointer to the gxPath
  159.             cube            ->        the cubic
  160.             count            ->        how many points to use
  161.         
  162. --------------------------------------------------------------------------------*/
  163.  
  164. void CubicPath( SmallPath *pathptr, const cubic *cube, const long count )
  165. {
  166.     long        *ptr;
  167.  
  168.     pathptr->contours = 1;
  169.     pathptr->count = count + 2;
  170.     pathptr->flags = 0x7FFFFFFF;
  171.     pathptr->flags &= ~( (unsigned long) 0x80000000 >> ( count + 1 ) );
  172.     
  173.     ptr = (Fixed *) &pathptr->data[ 0 ];
  174.     
  175.     *ptr++ = cube->a.x;
  176.     *ptr++ = cube->a.y;
  177.  
  178.     (void) ComputePoints( cube, count,(gxPoint *) ptr );
  179. }
  180. /*--------------------------------------------------------------------------------
  181.  
  182.     DrawCubic
  183.     
  184.         this routine draws a cubic with the given fill
  185.         
  186.             cube            ->        the cubic
  187.             theFill        ->        how it should be filled
  188.         
  189. --------------------------------------------------------------------------------*/
  190. void DrawCubic( const cubic *cube, gxShapeFill theFill )
  191. {
  192.     gxShape    sh = NewCubic( cube );
  193.     
  194.     if( theFill ) GXSetShapeFill( sh, theFill );
  195.  
  196.     GXDrawShape( sh );
  197.     GXDisposeShape( sh );
  198. }
  199. /*--------------------------------------------------------------------------------
  200.  
  201.     SetCubic
  202.     
  203.         this routine sets the points inside of a gxPath to be those of the given
  204.         cubic
  205.         
  206.             dest        ->        the gxShape to set
  207.             cube        ->        the cubic
  208.         
  209. --------------------------------------------------------------------------------*/
  210.  
  211. void SetCubic( gxShape dest, const cubic *cube )
  212. {
  213.     SmallPath        pathrec;
  214.  
  215.     CubicPath( &pathrec, cube, xCountQuadratics( cube ) );
  216.     
  217.     GXSetPaths( dest, (gxPaths *) &pathrec );
  218. }
  219. /*--------------------------------------------------------------------------------
  220.  
  221.     ComputePoints
  222.     
  223.         this routine is where the cuadratic points get computed.  note that this
  224.         routine never fills in the last gxPoint in the code.
  225.         
  226.             cubic            ->            a pointer to the cubic
  227.             count            ->            the number of points other than the two end ones
  228.                                                 that we need to generate.
  229.             storage        ->            a place to put the points that are generated
  230.  
  231. --------------------------------------------------------------------------------*/
  232. gxPoint *ComputePoints( const cubic *cube, long    count,  gxPoint *storage )
  233. {
  234.     Fixed        *ptr = (Fixed *) storage;
  235.     
  236.     /* this routine assumes that the first gxPoint has been moved in by the caller */        
  237.         
  238.     if( 0 < count )
  239.         {
  240.             xcubic    x;
  241.             
  242.             Fract        u;
  243.             Fract        n;
  244.             
  245.             Fixed            tempx1, tempy1;
  246.             Fixed            tempx2, tempy2;
  247.  
  248.             Fixed            ntempx1, ntempy1;
  249.             Fixed            ntempx2, ntempy2;
  250.             
  251.             /* we now need to compute the coefficients for this cubic -- for efficient computation later  */
  252.             
  253.             x.ax = -cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x;
  254.             x.ay = -cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y;
  255.             x.bx = 3 * cube->a.x - 6 * cube->b.x + 3 * cube->c.x;
  256.             x.by = 3 * cube->a.y - 6 * cube->b.y + 3 * cube->c.y;
  257.             x.cx = -3 * cube->a.x + 3 * cube->b.x;
  258.             x.cy = -3 * cube->a.y + 3 * cube->b.y;
  259.             x.dx = cube->a.x;
  260.             x.dy = cube->a.y;
  261.             
  262.             n = FracDiv( 1, count );            /*        LONGINT / LONGINT -> frac        */
  263.             u = n;
  264.             
  265.             /* store the first pair of values */
  266.             
  267.             tempx1 = cube->a.x >> 1;
  268.             tempx2 = FracMul( x.cx, n ) >> 2;
  269.             
  270.             tempy1 = cube->a.y >> 1;
  271.             tempy2 = FracMul( x.cy, n ) >> 2;
  272.             
  273.             /* we start here  */
  274.             
  275.             for( ; 0 < count; --count )
  276.                 {
  277.                     /* compute the next gxPoint sequence */
  278.                     
  279.                     ntempx1 = xcube( &x, u ) >> 1;
  280.                     ntempx2 = FracMul( xcubeprime( &x, u ), n ) >> 2;
  281.  
  282.                     ntempy1 = ycube( &x, u ) >> 1;
  283.                     ntempy2 = FracMul( ycubeprime( &x, u ), n ) >> 2;
  284.                     
  285.                     /* now store the gxPoint */
  286.                     
  287.                     *ptr++ = tempx1 + tempx2 + ntempx1 - ntempx2;
  288.                     *ptr++ = tempy1 + tempy2 + ntempy1 - ntempy2;
  289.                     
  290.                     tempx1 = ntempx1;
  291.                     tempx2 = ntempx2;
  292.  
  293.                     tempy1 = ntempy1;
  294.                     tempy2 = ntempy2;
  295.                     
  296.                     u += n;
  297.                 }
  298.  
  299.             /* move in the last gxPoint of the cubic */
  300.  
  301.             *ptr++ = cube->d.x;
  302.             *ptr++ = cube->d.y;
  303.  
  304.         }
  305.     return((gxPoint *) ptr );
  306. }
  307.  
  308. /*--------------------------------------------------------------------------------
  309.  
  310.     xCountQuadratics
  311.     
  312.         this routine calculates the number of cubics that would be needed
  313.         to draw a with no more than a pixel error.
  314.         
  315.             cubic            ->            a pointer to the cubic
  316.  
  317. --------------------------------------------------------------------------------*/
  318.  
  319. long xCountQuadratics( const cubic *cube )
  320. {
  321.     Fixed        ax, ay;
  322.     
  323.     short        temp;
  324.     long         count;
  325.     
  326.     /* first get the a vector components */
  327.     
  328.     ax = -cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x;
  329.     ay = -cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y;
  330.     
  331.     /* now make sure that they are positive */
  332.     
  333.     if( ax < 0 ) ax = -ax;
  334.     if( ay < 0 ) ay = -ay;
  335.     
  336.     /* now we need to pick the max one */
  337.     
  338.     ax = ( ay < ax ) ? ax : ay;
  339.     
  340.     /* we now divide by twenty and take the ceiling         */
  341.  
  342.     /*        NOTE: if you want the tolerance to be .5 then     */
  343.     /*        divide ax by 10, .25 -> 5, etc                                    */
  344.     
  345.     temp = ( FixDiv( ax, ff( 20 ) ) + 0xFFFF ) >> 16;
  346.         
  347.     /* this is a crude but fast and effective way of taking the cube root of        */
  348.     /* 'temp' which is between 0 and 27000                                                                            */
  349.     
  350.     if( temp <= 4096 )
  351.         {
  352.             if( temp <= 512 )
  353.                 {
  354.                     if( temp <= 64 )
  355.                         {
  356.                             if( temp <= 8 )
  357.                                 {
  358.                                     if( temp <= 1 )
  359.                                         count = 1;
  360.                                     else
  361.                                         count = 2;
  362.                                 }
  363.                             else
  364.                                 {
  365.                                     if( temp <= 27 )
  366.                                         count = 3;
  367.                                     else
  368.                                         count = 4;
  369.                                 }
  370.                         }
  371.                     else
  372.                         {
  373.                             if( temp <= 216 )
  374.                                 {
  375.                                     if( temp <= 125 )
  376.                                         count = 5;
  377.                                     else
  378.                                         count = 6;
  379.                                 }
  380.                             else
  381.                                 {
  382.                                     if( temp <= 343 )
  383.                                         count = 7;
  384.                                     else
  385.                                         count = 8;
  386.                                 }
  387.                         }
  388.                 }
  389.             else
  390.                 {
  391.                     if( temp <= 1728 )
  392.                         {
  393.                             if( temp <= 1000 )
  394.                                 {
  395.                                     if( temp <= 729 )
  396.                                         count = 9;
  397.                                     else
  398.                                         count = 10;
  399.                                 }
  400.                             else
  401.                                 {
  402.                                     if( temp <= 1331 )
  403.                                         count = 11;
  404.                                     else
  405.                                         count = 12;
  406.                                 }
  407.                         }
  408.                     else
  409.                         {
  410.                             if( temp <= 2744 )
  411.                                 {
  412.                                     if( temp <= 2197 )
  413.                                         count = 13;
  414.                                     else
  415.                                         count = 14;
  416.                                 }
  417.                             else
  418.                                 {
  419.                                     if( temp <= 3375 )
  420.                                         count = 15;
  421.                                     else
  422.                                         count = 16;
  423.                                 }
  424.                         }
  425.                 }
  426.         }
  427.     else
  428.         {
  429.             if( temp <= 13824 )
  430.                 {
  431.                     if( temp <= 8000 )
  432.                         {
  433.                             if( temp <= 5832 )
  434.                                 {
  435.                                     if( temp <= 4913 )
  436.                                         count = 17;
  437.                                     else
  438.                                         count = 18;
  439.                                 }
  440.                             else
  441.                                 {
  442.                                     if( temp <= 6859 )
  443.                                         count = 19;
  444.                                     else
  445.                                         count = 20;
  446.                                 }
  447.                         }
  448.                     else
  449.                         {
  450.                             if( temp <= 10648 )
  451.                                 {
  452.                                     if( temp <= 9261 )
  453.                                         count = 21;
  454.                                     else
  455.                                         count = 22;
  456.                                 }
  457.                             else
  458.                                 {
  459.                                     if( temp <= 12167 )
  460.                                         count = 23;
  461.                                     else
  462.                                         count = 24;
  463.                                 }
  464.                         }
  465.                 }
  466.             else
  467.                 {
  468.                     if( temp <= 21952 )
  469.                         {
  470.                             if( temp <= 17576 )
  471.                                 {
  472.                                     if( temp <= 15625 )
  473.                                         count = 25;
  474.                                     else
  475.                                         count = 26;
  476.                                 }
  477.                             else
  478.                                 {
  479.                                     if( temp <= 19683 )
  480.                                         count = 27;
  481.                                     else
  482.                                         count = 28;
  483.                                 }
  484.                         }
  485.                     else
  486.                         {
  487.                             if( temp <= 27000 )
  488.                                 {
  489.                                     if( temp <= 24389 )
  490.                                         count = 29;
  491.                                     else
  492.                                         count = 30;
  493.                                 }
  494.                             else
  495.                                 {
  496.                                     /* because our gxPath can only contain 32 -2 points we stop here */
  497.                                 
  498.                                     count = 30;
  499.                                 }
  500.                         }
  501.                 }
  502.         }
  503.         
  504.     return( count );
  505. }